package com.gitee.aspect;

import com.gitee.annotation.AutoFill;
import com.gitee.constant.AutoFillConstant;
import com.gitee.context.BaseContext;
import com.gitee.enumeration.OperationType;
import lombok.extern.slf4j.Slf4j;
import org.apache.poi.ss.usermodel.DataFormatter;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.stereotype.Component;

import java.lang.reflect.Method;
import java.text.SimpleDateFormat;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;

/**
 * 自定义切面, 实现公共字段自动填充处理逻辑
 */
@Aspect
@Component
@Slf4j
public class AutoFillAspect {

    /**
     * 任意返回值, com.sky.mapper下所有的类, 类下的所有参数的所有方法
     * 并且有AutoFill注解的方法
     */
    @Pointcut("execution(* com.gitee.mapper.*.*(..)) && @annotation(com.gitee.annotation.AutoFill)")
    public void autoFillPointCut() {
    }

    // 前置通知, 进行公共字段赋值
    @Before("autoFillPointCut()")
    public void autoFill(JoinPoint joinPoint) {
        log.info("开始进行公共字段填充");
        // 通过joinPoint获得MethodSignature
        MethodSignature signature = (MethodSignature) joinPoint.getSignature();

        // 通过signature获取方法上的注解
        AutoFill annotation = signature.getMethod().getAnnotation(AutoFill.class);

        // 得到注解中的值, 判断是insert还是update
        // 因为这两个操作不一样, insert需要填充四个数据, 而update只需要两个
        OperationType value = annotation.value();

        // 获得方法的所有参数
        Object[] args = joinPoint.getArgs();
        if (args == null || args.length == 0) {
            return;
        }

        // 只获取第一个参数, 若想使用自动填充, 必须把实体参数放到第一个
        Object arg = args[0];

        // 准备数据
        LocalDateTime now = LocalDateTime.now();
        Integer currentId = BaseContext.getCurrentId();

        // 格式化日期
        String formatDateTime = now.format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"));
        try {
            // 不同情况执行不同方法
            // 为方法的形参赋值
            if (value == OperationType.INSERT) {
                Method setCreateTime = arg.getClass().getDeclaredMethod(AutoFillConstant.SET_CREATE_TIME, String.class);
                Method setCreateUser = arg.getClass().getDeclaredMethod(AutoFillConstant.SET_USER_ID, Integer.class);
                Method getUserId = arg.getClass().getDeclaredMethod(AutoFillConstant.GET_USER_ID);
                log.info("时间: {}", now);
                setCreateTime.invoke(arg, formatDateTime);

                // 只有userId为null 才进行赋值
                Object result = getUserId.invoke(arg);
                if (result == null) {
                    setCreateUser.invoke(arg, currentId);
                }
            } else if (value == OperationType.UPDATE) {
                // 使用获得对应set方法
                Method setUpdateTime = arg.getClass().getDeclaredMethod(AutoFillConstant.SET_UPDATE_TIME, String.class);
                setUpdateTime.invoke(arg, formatDateTime);
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}
